<!-- ChatInterface.vue -->
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import { ref } from 'vue'
import { ChatDotRound, UserFilled, Delete } from '@element-plus/icons-vue'
import { useInstructionStore } from '@/stores/modules/instruction'
import { useInstructionResultStore } from '@/stores/modules/instructionResult'
import type { AIResponse } from '@/types/AIResponse'
import { useRouter } from 'vue-router'
import { createJsonTranslator, createOpenAILanguageModel } from 'typechat'
import { createTypeScriptJsonValidator } from 'typechat/ts'

const model = createOpenAILanguageModel(
  'sk-klndtfehdzxiyvcthtgzhljxxogwpowqarpxfolpljmkeini',
  'Pro/deepseek-ai/DeepSeek-V3',
  'https://api.siliconflow.cn/v1/chat/completions',
)
// 加载 Schema 文件
const schema = `/**
 * 城市规划AI指令系统响应协议
 * @context 当用户需求明确时返回指令，信息不足时要求澄清
 * @rule 所有指令必须包含可执行的明确地理要素操作，避免模糊不清的指令
 * @rule 你必须有一定的判断能力，在信息充分时直接执行，不要过度向用户提问
 * @rule 返回纯json数据，无需任何其他内容，确保格式正确可解析
 * @rule 优先考虑用户意图，尽量一次性完成复杂操作而非拆分多次交互
 * @rule 你不需要地理数据数据，只需要属性数据
 * @rule 你只需要填充下面指定的参数，其他不用你考虑
 */
export type AIResponse = InstructionResponse | QuestionResponse

/**
 * 指令模式响应
 * @scenario 当用户提供完整要素信息时使用，如明确的要素类型、名称和操作
 * @example {"type":"instruction","actions":[{"action":"ADD_FEATURE","layerType":"POLYGON","params":{"attributes":{"name":"新建学校"},"bufferParams":{"distance":50}}]}
 * @priority 当信息充分时，优先使用指令模式而非提问模式
 */
interface InstructionResponse {
  /**
   * 响应类型标识
   * @const "instruction"
   * @errorMessage 类型字段缺失或不合法
   */
  type: 'instruction'

  /**
   * 操作指令队列
   * @validation 至少包含1个有效指令
   * @priority 按指令顺序执行，确保前后依赖关系正确
   * @example 添加要素后创建缓冲区
   * @rule 相关联的操作应放在同一队列中顺序执行
   */
  actions: Instruction[]
}

/**
 * 询问模式响应
 * @scenario 当缺少名称、存在矛盾或需要补充细节时使用
 * @example {"type":"question","content":"请说明要删除的要素名称"}
 * @rule 仅在关键信息缺失且无法推断时使用，避免过度提问
 */
interface QuestionResponse {
  /**
   * 响应类型标识
   * @const "question"
   * @errorMessage 问题类型不匹配
   */
  type: 'question'

  /**
   * 澄清问题内容
   * @rule 必须用中文提出具体问题，避免模糊或开放式问题
   * @validation 问题必须可操作且明确，指向特定缺失信息
   * @errorMessage 问题内容不能为空
   * @example "请确认要修改的公园名称"
   * @rule 问题应当简洁明了，一次只询问一个关键信息
   */
  content: string
}

/**
 * 地理要素操作指令
 * @context 每个指令对应一个原子地理操作，复杂操作应拆分为多个原子操作
 * @rule 指令应当明确、具体、可执行，避免模糊表述
 */
export type Instruction = {
  /**
   * 操作类型
   * @choice CREATE_BUFFER 创建缓冲区 - 在要素周围创建指定距离的缓冲区
   * @choice ADD_FEATURE 添加要素 - 在地图上新增一个地理要素
   * @choice UPDATE_FEATURE 修改要素属性 - 更新已有要素的属性信息
   * @choice REMOVE_FEATURE 删除要素 - 从地图上移除指定要素
   * @choice QUERY_FEATURE 查询要素 - 根据条件查询符合的要素
   * @choice MEASURE_DISTANCE 测量距离 - 测量两点或多点之间的距离
   * @choice MEASURE_AREA 测量面积 - 计算指定区域的面积
   * @choice HEATMAP_GENERATION 热力图生成 - 根据点密度生成热力图
   * @choice GENERATE_REPORT 生成报表 - 根据指定条件生成统计分析报表
   * @case REMOVE_FEATURE 删除时：
   *   - 若用户选择手动删除，仅需包含图层类型
   *   - 若按名称删除，需包含完整名称和图层类型
   * @case CREATE_FEATURE 创建时：
   *   - 无需包含地理位置
   *   - 需包含attributes
   * @errorMessage 无效的操作类型
   * @rule 根据用户意图选择最合适的操作类型
   */
  action:
    | 'CREATE_BUFFER'
    | 'ADD_FEATURE'
    | 'UPDATE_FEATURE'
    | 'REMOVE_FEATURE'
    | 'QUERY_FEATURE'
    | 'MEASURE_DISTANCE'
    | 'MEASURE_AREA'
    | 'HEATMAP_GENERATION'
    | 'GENERATE_REPORT'
    | 'QUERY_SURROUNDING'

  /**
   * 地理要素类型
   * @choice POLYGON 面要素（区域、建筑轮廓、用地范围）
   * @choice LINE 线要素（道路、河流、边界线）
   * @choice POINT 点要素（设施点位、兴趣点）
   * @relation 与操作类型关联校验：
   *   - CREATE_BUFFER 需配合线/面要素
   *   - 不同要素类型适用于不同的地理实体
   * @errorMessage 图层类型与操作不匹配
   * @rule 根据实际地理实体特征选择合适的要素类型
   */
  layerType: 'POLYGON' | 'LINE' | 'POINT'

  /**
   * 操作参数集
   * @validation 必须包含attributes
   * @rule 参数应当完整且符合对应操作的要求
   */
  params: InstructionParams
}

/**
 * 指令参数结构
 * @context 不同操作类型参数会有差异
 * @rule 根据操作类型提供相应的必要参数
 */
export type InstructionParams = {
  /**
   * 要素特征属性
   * @rule 必须包含唯一标识名称，确保可被引用和识别
   * @validation 名称需符合命名规范
   * @errorMessage 要素名称不能为空
   * @example { name: "中山公园" }
   * @rule 属性应当准确描述要素特征
   */
  attributes: {
    /**
     * 要素标识名称
     * @validation 2-20个中文字符
     * @example "北区消防站"
     * @rule 名称应当简洁明了，具有描述性
     */
    name: string

    /**
     * 建筑类型（点要素）
     * @condition 仅当layerType=POINT时有效
     * @example "学校"、"医院"、"商场"、"政府机构"
     * @rule 应使用标准化的建筑类型术语
     */
    BuildingType?: string

    /**
     * 道路类型（线要素）
     * @condition 仅当layerType=LINE时有效
     * @example "主干道"、"次干道"、"支路"、"人行道"
     * @rule 应符合城市道路分级标准
     */
    RoadType?: string

    /**
     * 区域类型（面要素）
     * @condition 仅当layerType=POLYGON时有效
     * @example "商业区"、"居住区"、"工业区"、"绿地"
     * @rule 应符合城市用地分类标准
     */
    ServiceType?: string

    /**
     * 要素描述
     * @example "这是一个新建的要素描述"
     * @rule 描述应当简洁且包含关键信息
     */
    description?: string
  }

  /**
   * 缓冲区参数
   * @condition 仅当action=CREATE_BUFFER时有效
   * @validation 10-1000米范围
   * @errorMessage 缓冲区距离超出范围
   * @example { distance: 50 }
   * @rule 缓冲距离应当合理且符合实际需求
   */
  bufferParams?: {
    /**
     * 缓冲距离（米）
     * @unit 米
     * @validation number > 0
     * @rule 根据实际需求设置合适的缓冲距离
     */
    distance: number
  }

  /**
   * 查询参数
   * @condition 仅当action=QUERY_FEATURE时有效
   * @rule 查询条件应当明确且可执行
   */
  queryParams?: {
    /**
     * 查询条件表达式
     * @example "name LIKE '%公园%'"
     * @example "BuildingType = '学校'"
     * @rule 使用标准SQL语法构建查询条件
     */
    condition: string
  }

  /**
   * 测量距离参数
   * @condition 仅当action=MEASURE_DISTANCE时有效
   * @rule 测量参数应当明确且可执行
   */
  measureDistanceParams?: {
    /**
     * 测量单位
     * @example "meters"、"kilometers"
     * @rule 默认使用"meters'作为默认单位
     * @rule 使用标准距离单位
     */
    unit?: string
  }

  /**
   * 测量面积参数
   * @condition 仅当action=MEASURE_AREA时有效
   * @rule 测量参数应当明确且可执行
   */
  measureAreaParams?: {
    /**
     * 测量单位
     * @example "square-meters"、"square-kilometers"、"hectares"
     * @rule 使用标准面积单位
     */
    unit?: string
  }

  /**
   * 热力图生成参数
   * @condition 仅当action=HEATMAP_GENERATION时有效
   * @rule 热力图参数应当明确且可执行
   */
  heatmapParams?: {
    /**
     * 热力图半径
     * @unit 像素
     * @validation number > 0
     * @rule 根据实际需求设置合适的热力图半径
     */
    radius?: number

    /**
     * 热力图模糊度
     * @validation 0-1范围
     * @rule 值越大，热力图越模糊
     */
    blur?: number

    /**
     * 热力图颜色渐变
     * @example ["blue", "purple", "red"]
     * @rule 从低到高的颜色渐变
     */
    gradient?: string[]
  }

  /**
   * 报表生成参数
   * @condition 仅当action=GENERATE_REPORT时有效
   * @rule 报表参数应当明确且可执行
   */
  reportParams?: {
    /**
     * 报表类型
     * @example "pie"、"bar"、"line"、"scatter"
     * @rule 使用ECharts支持的图表类型
     */
    chartType: string

    /**
     * 报表标题
     * @example "区域建筑类型分布"
     * @rule 标题应当简洁明了
     */
    title: string

    /**
     * 数据查询条件
     * @example "BuildingType IS NOT NULL"
     * @rule 使用标准SQL语法构建查询条件
     */
    condition?: string

    /**
     * 分组字段
     * @example "BuildingType"
     * @rule 用于分组统计的字段名
     */
    groupBy?: string
  }

  /**
   * 周围位置查询参数
   * @condition 仅当action=QUERY_SURROUNDING时有效
   * @rule 查询参数应当明确且可执行
   */
  surroundingParams?: {
    /**
     * 中心点经度
     * @validation number
     * @rule 必须是有效的经度值
     */
    longitude: number

    /**
     * 中心点纬度
     * @validation number
     * @rule 必须是有效的纬度值
     */
    latitude: number

    /**
     * 设施类型代码
     * @example ’050000‘ | ’060000‘ | ’070000‘ | ’080000‘ | ’090000‘ | ’100000‘ | ’110000‘ | ’120000‘ | ’150000‘ | ’011100‘ | ’150500‘
     * @rule 使用高德地图POI类型代码
     * @const {
     *   RESTAURANT: '050000' - 餐饮
     *   SHOPPING: '060000' - 购物
     *   LIFE_SERVICE: '070000' - 生活服务
     *   ENTERTAINMENT: '080000' - 休闲娱乐
     *   MEDICAL: '090000' - 医疗
     *   HOTEL: '100000' - 住宿
     *   SCENIC_SPOT: '110000' - 风景名胜
     *   BUSINESS: '120000' - 商务
     *   TRANSPORTATION: '150000' - 交通设施
     *   CHARGING_STATION: '011100' - 充电站
     *   SUBWAY_STATION: '150500' - 地铁站
     * }
     */
    facilityType: string

    /**
     * 搜索半径，单位：米
     * @unit 米
     * @validation number > 0
     * @rule 根据实际需求设置合适的搜索半径
     */
    radius?: number
  }
}
`

// 创建验证器
const validator = createTypeScriptJsonValidator<AIResponse>(schema, 'AIResponse')

// 创建 JSON 转换器
const planningTranslator = createJsonTranslator(model, validator)

const router = useRouter()

interface Message {
  id: number
  content: string
  isAI: boolean
  timestamp: number
}

// 初始欢迎消息
const welcomeMessage = {
  id: 1,
  content:
    '您好！我是城市规划AI助手，请描述您的规划需求。例如：在北区新建住宅区，并配套学校和公园。',
  isAI: true,
  timestamp: Date.now(),
}

// 初始化消息列表
const messages = ref<Message[]>([{ ...welcomeMessage }])
const inputText = ref('')
const isLoading = ref(false)

// 完整处理函数
const handleSend = async () => {
  try {
    if (!inputText.value.trim()) return

    // 添加用户消息
    messages.value.push({
      id: Date.now(),
      content: inputText.value,
      isAI: false,
      timestamp: Date.now(),
    })

    // 提示AI响应
    isLoading.value = true

    try {
      // 获取指令执行结果存储
      const instructionResultStore = useInstructionResultStore()

      // 获取最近的查询结果
      const recentQueryResults = instructionResultStore.getQueryResults

      let inputMessage = ''
      messages.value.forEach((msg) => {
        // 遍历消息，发送给 AI 模型
        if (msg.isAI) {
          inputMessage += '[assistant]:' + msg.content + '.\n'
        } else {
          inputMessage += '[user]:' + msg.content + '.\n'
        }
      })

      // 添加历史查询结果的上下文信息
      if (recentQueryResults.length > 0) {
        inputMessage += '\n[context]:以下是之前查询到的要素信息，你可以在回答中参考这些信息：\n'

        recentQueryResults.forEach((result, index) => {
          if (result.action === 'QUERY_FEATURE' && result.resultData?.attributes) {
            const attrs = result.resultData.attributes
            const layerType = result.layerType
            const geoInfo = result.resultData.geometryInfo

            inputMessage += `查询结果${index + 1}：\n`
            inputMessage += `- 类型：${layerType === 'POINT' ? '点要素' : layerType === 'LINE' ? '线要素' : '面要素'}\n`

            // 添加名称信息
            if (layerType === 'POINT' && attrs.BuildingName) {
              inputMessage += `- 名称：${attrs.BuildingName}\n`
            } else if (layerType === 'LINE' && attrs.RoadName) {
              inputMessage += `- 名称：${attrs.RoadName}\n`
            } else if (layerType === 'POLYGON' && attrs.AreaName) {
              inputMessage += `- 名称：${attrs.AreaName}\n`
            }

            // 添加位置信息
            if (geoInfo) {
              if (geoInfo.type === 'point') {
                inputMessage += `- 位置：经度 ${geoInfo.longitude.toFixed(6)}，纬度 ${geoInfo.latitude.toFixed(6)}\n`
              } else if (geoInfo.type === 'polygon' && geoInfo.centroid) {
                inputMessage += `- 中心位置：经度 ${geoInfo.centroid.longitude.toFixed(6)}，纬度 ${geoInfo.centroid.latitude.toFixed(6)}\n`
                inputMessage += `- 面积：${(geoInfo.area / 10000).toFixed(2)} 公顷\n`
              }
            }
          } else if (result.action === 'QUERY_SURROUNDING' && result.resultData?.poiList) {
            const poiList = result.resultData.poiList
            const params = result.resultData.surroundingParams

            inputMessage += `周边查询结果${index + 1}：\n`
            inputMessage += `- 查询中心：经度 ${params.longitude.toFixed(6)}，纬度 ${params.latitude.toFixed(6)}\n`
            inputMessage += `- 设施类型：${params.facilityType}\n`
            inputMessage += `- 查询半径：${params.radius || 1000} 米\n`
            inputMessage += `- 找到设施数量：${poiList.length}\n`

            // 添加前3个POI点的信息
            const topPois = poiList.slice(0, 3)
            if (topPois.length > 0) {
              inputMessage += `- 主要设施：\n`
              topPois.forEach((poi: { name: string; distance: number }, i: number) => {
                inputMessage += `  ${i + 1}. ${poi.name}，距离 ${poi.distance} 米\n`
              })
            }
          }
        })
      }

      // 🔥 核心变化点：用 TypeChat 接管 AI 交互
      const response = await planningTranslator.translate(inputMessage)
      if (!response.success) {
        ElMessage.error(`格式错误：${response.message}`)
        return
      }
      let responseData = response.data

      if (responseData.type === 'question') {
        // 处理询问模式
        messages.value.push({
          id: Date.now(),
          content: responseData.content,
          isAI: true,
          timestamp: Date.now(),
        })
      } else {
        // 处理指令模式
        const instructions = responseData.actions
        // 生成中文提示
        const actionMap: Record<string, string> = {
          ADD_FEATURE: '添加要素',
          UPDATE_FEATURE: '修改要素',
          REMOVE_FEATURE: '删除要素',
          CREATE_BUFFER: '创建缓冲区',
        }

        const layerMap: Record<string, string> = {
          POLYGON: '面图层',
          LINE: '线图层',
          POINT: '点图层',
        }

        const aiMessage = instructions
          .map(
            (i) =>
              `• ${actionMap[i.action] || i.action}（${layerMap[i.layerType] || i.layerType}）：${i.params.attributes?.name || '未命名'}`,
          )
          .join('\n')

        messages.value.push({
          id: Date.now() + 1,
          content: `已生成方案：\n${aiMessage}`,
          isAI: true,
          timestamp: Date.now(),
        })

        // 存储指令
        const store = useInstructionStore()
        store.setInstructions(instructions)

        // 跳转确认
        ElMessageBox.confirm('已成功生成地图要素，是否立即跳转到地图界面？', '操作成功', {
          confirmButtonText: '立即跳转',
          cancelButtonText: '稍后处理',
          type: 'success',
        })
          .then(() => {
            router.push('/Admin/map')
          })
          .catch(() => {
            ElMessage({
              type: 'info',
              message: '您可以在侧边栏随时进入地图界面查看',
              duration: 3000,
            })
          })
      }
    } catch (error: any) {
      // 错误处理
      console.error('[处理流程错误]', error)
      ElMessage.error({
        message: `操作失败：${error.message}`,
        duration: 5000,
        showClose: true,
      })
    }
  } catch (error) {
  } finally {
    isLoading.value = false
    inputText.value = ''
  }
}

const handleExampleClick = (example: string) => {
  inputText.value = example
}

// 添加清空聊天记录的方法
const clearChatHistory = () => {
  ElMessageBox.confirm('确定要清空所有聊天记录吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(() => {
      // 重置为初始欢迎消息
      messages.value = [
        {
          ...welcomeMessage,
          timestamp: Date.now(),
        },
      ]
      ElMessage.success('聊天记录已清空')
    })
    .catch(() => {
      // 用户取消操作
    })
}
</script>

<template>
  <div class="chat-container">
    <!-- 添加顶部操作栏 -->
    <div class="chat-header">
      <div class="title">城市规划AI助手</div>
      <el-button type="danger" size="small" plain @click="clearChatHistory" class="clear-button">
        <el-icon><Delete /></el-icon>
        清空聊天
      </el-button>
    </div>

    <!-- 对话主体区域 -->
    <div class="chat-messages">
      <div
        v-for="msg in messages"
        :key="msg.id"
        class="message-bubble"
        :class="{ 'ai-message': msg.isAI, 'user-message': !msg.isAI }"
      >
        <el-icon class="avatar">
          <component :is="msg.isAI ? ChatDotRound : UserFilled" />
        </el-icon>
        <div class="content">
          <div class="text" v-html="msg.content.replace(/\n/g, '<br/>')"></div>
          <div class="timestamp">
            {{ new Date(msg.timestamp).toLocaleTimeString() }}
          </div>
        </div>
      </div>
      <div v-if="isLoading" class="loading-indicator">
        <el-icon class="is-loading"><Loading /></el-icon>
        思考中...
      </div>
    </div>

    <!-- 快捷操作区域 -->
    <div class="quick-actions">
      <div class="action-card" @click="handleExampleClick('规划一个社区中心,只要一个地方')">
        <el-icon><OfficeBuilding /></el-icon>
        <span>社区中心规划</span>
      </div>
      <div class="action-card" @click="handleExampleClick('在湖畔区域增加生态公园和步行道系统')">
        <el-icon><Star /></el-icon>
        <span>绿地规划</span>
      </div>
      <div class="action-card" @click="handleExampleClick('优化现有交通网络，增加智能公交站')">
        <el-icon><Position /></el-icon>
        <span>交通优化</span>
      </div>
    </div>

    <!-- 输入区域 -->
    <div class="input-area">
      <el-input
        v-model="inputText"
        type="textarea"
        :rows="3"
        placeholder="输入规划需求，例如：在南部开发区建设产业园，配套员工宿舍和商业街"
        resize="none"
        @keydown.enter.exact.prevent="handleSend"
      />
      <el-button
        type="primary"
        class="send-button"
        :disabled="!inputText.trim()"
        @click="handleSend"
      >
        发送
        <el-icon class="ml-2"><Promotion /></el-icon>
      </el-button>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.chat-container {
  height: calc(100vh - 60px);
  display: flex;
  flex-direction: column;
  background: #f5f7fa;

  /* 添加顶部操作栏样式 */
  .chat-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 20px;
    background: white;
    border-bottom: 1px solid #ebeef5;

    .title {
      font-size: 16px;
      font-weight: 500;
      color: #303133;
    }

    .clear-button {
      display: flex;
      align-items: center;
      gap: 5px;
    }
  }

  .chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 18px;

    .message-bubble {
      max-width: 75%;
      display: flex;
      gap: 12px;

      .avatar {
        font-size: 24px;
        padding: 8px;
        background: white;
        border-radius: 50%;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
      }

      .content {
        flex: 1;
        padding: 12px 16px;
        border-radius: 12px;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);

        .text {
          white-space: pre-wrap;
          line-height: 1.6;
        }

        .timestamp {
          margin-top: 8px;
          font-size: 12px;
          color: #909399;
          text-align: right;
        }
      }

      &.ai-message {
        align-self: flex-start;

        .avatar {
          color: #409eff;
        }

        .content {
          background: white;
          border: 1px solid #ebeef5;
        }
      }

      &.user-message {
        align-self: flex-end;
        flex-direction: row-reverse;

        .avatar {
          color: #67c23a;
        }

        .content {
          background: #ecf5ff;
          border: 1px solid #d9ecff;
        }
      }
    }

    .loading-indicator {
      display: flex;
      align-items: center;
      gap: 8px;
      color: #909399;
      padding: 12px 24px;
    }
  }

  .quick-actions {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    padding: 0 20px 12px;

    .action-card {
      background: white;
      border-radius: 8px;
      padding: 12px;
      display: flex;
      align-items: center;
      gap: 8px;
      cursor: pointer;
      transition: all 0.2s;
      border: 1px solid transparent;

      &:hover {
        border-color: #409eff;
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1);
      }

      .el-icon {
        font-size: 20px;
        color: #409eff;
      }

      span {
        font-size: 14px;
        color: #606266;
      }
    }
  }

  .input-area {
    position: relative;
    border-top: 1px solid #ebeef5;
    background: white;
    padding: 16px;

    :deep(.el-textarea__inner) {
      border: none;
      box-shadow: none !important;
      padding-right: 80px;
    }

    .send-button {
      position: absolute;
      bottom: 28px;
      right: 20px;
      padding: 8px 16px;
      border-radius: 8px;
    }
  }
}
// 在模板中添加询问样式
.ai-message.question {
  .content {
    background-color: #f0f4ff;
    border-color: #c6d9ff;
  }
}
</style>
